﻿using Ops.Mpc.States;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;

namespace Ops.Mpc.Models
{
    /// <summary>
    /// BusyIndicatorModel is a special model that can be used for busy indicators.  It uses
    /// reference counting to keep track if the indicator should be turned on or off
    /// </summary>
    public class BusyIndicatorModel : Model<BusyIndicatorModel>, IBusyIndicatorModel
    {
        #region Fields & Properties
        private bool _isBusy = false;
        private Visibility _visibility = Visibility.Collapsed;
        private Dictionary<AsyncAction, int> _counts = new Dictionary<AsyncAction, int>();
        private object _lock = new object();
        private string _busyMessage = string.Empty;
        

        /// <summary>
        /// The message for the busy indicator to show
        /// </summary>
        public string BusyMessage
        {
            get
            {
                return _busyMessage;
            }

            set
            {
                this._busyMessage = value;
                this.RaisePropertyChanged(model => model.BusyMessage);
            }
        }

        /// <summary>
        /// A property that can be used to bind to a busy indicator
        /// </summary>
        public bool IsBusy
        {
            get
            {
                return this._isBusy;
            }

            private set
            {
                if (this._isBusy != value)
                {
                    this._isBusy = value;
                    this.RaisePropertyChanged(m => m.IsBusy);
                }
            }

        }

        /// <summary>
        /// A property that can be used to bind to a busy indicator
        /// </summary>
        public Visibility Visibility
        {
            get
            {
                return this._visibility;
            }

            private set
            {
                if (this._visibility != value)
                {
                    this._visibility = value;
                    this.RaisePropertyChanged(m => m.Visibility);
                }
            }
        }
        #endregion

        #region Methods

        protected virtual void MakeBusy(AsyncAction asyncAction)
        {
            lock (_lock)
            {
                int count = 0;

                _counts.TryGetValue(asyncAction, out count);
                _counts[asyncAction] = ++count;
                this.IsBusy = true;
                this.Visibility = Visibility.Visible;
                Debug.WriteLine("Make busy for {0} count: {1}, IsBusy = true", asyncAction.ItemName, count);
            }

        }

        protected virtual void MakeNotBusy(AsyncAction asyncAction)
        {
            lock (_lock)
            {
                int count = 0;
                if (_counts.TryGetValue(asyncAction, out count))
                {
                    count--;
                    if (count < 1)
                    {
                        _counts.Remove(asyncAction);

                        if (this._counts.Keys.Count < 1)
                        {
                            this.IsBusy = false;
                            this.Visibility = Visibility.Collapsed;
                            Debug.WriteLine("Make not busy for {0} count: {1}, IsBusy = false", asyncAction.ItemName, count);
                        }
                    }
                    else
                    {
                        _counts[asyncAction] = count;
                        Debug.WriteLine("Make not busy for {0} count: {1}", asyncAction.ItemName, count);
                    }


                }

            }
        }
        #endregion

        #region IBusyIndicatorModel Methods
        void IBusyIndicatorModel.MakeBusy(AsyncAction asyncAction)
        {
            this.MakeBusy(asyncAction);
        }

        void IBusyIndicatorModel.MakeNotBusy(AsyncAction asyncAction)
        {
            this.MakeNotBusy(asyncAction);
        }
        #endregion
    }
}
